﻿using Behaving.Composites;
using Behaving.Decorators;
using CrowdPleaser.Core.Utilities;
using NUnit.Framework;

namespace Behaving.Tests.DecoratorTests
{
    [TestFixture]
    public class DurationActionTests
    {
        // The first time the duration is run, it starts
        // When the time runs out, it stops

        // The second time the duration is run, it starts with a new batch of time
        [Test]
        public void When_a_duration_is_used()
        {
            ExecutionCounter before;
            ExecutionCounter after;
            ExecutionCounter inner;
            TimeManager.CurrentTime = 0;
            ExecutionCounter pre;

            BehaviourTree bt =
                new BehaviourTree(
                    new PriortySelector(
                        pre = new ExecutionCounter(RunningState.Failure),
                        new Sequence(
                            before = new ExecutionCounter(RunningState.Running),
                            new Duration(
                                10,
                                inner = new ExecutionCounter(RunningState.Running)),
                            after = new ExecutionCounter(RunningState.Success))));

            // First tick, before is running
            bt.Tick();
            Assertions.AssertWasStartedAndExecuted(before);
            Assertions.AssertWasNotCalled(inner);
            Assertions.AssertWasNotCalled(after);

            // Second tick, before is done, 
            // Inner is running
            TimeManager.CurrentTime = 1;
            before.RunningState = RunningState.Success;
            bt.Tick();
            Assertions.AssertWasExecutedAndStopped(before);
            Assertions.AssertWasStartedAndExecuted(inner);
            Assertions.AssertWasNotCalled(after);

            // Third tick, still time to run our duration
            TimeManager.CurrentTime = 7;
            bt.Tick();
            Assertions.AssertWasNotCalled(before);
            Assertions.AssertWasExecuted(inner);
            Assertions.AssertWasNotCalled(after);

            // Fourth tick, time to stop
            TimeManager.CurrentTime = 12;
            bt.Tick();
            Assertions.AssertWasNotCalled(before);
            Assertions.AssertWasStopped(inner);
            Assertions.AssertWasStartedExecutedAndStopped(after);

            // Sixth time, leaving
            pre.RunningState = RunningState.Success;
            bt.Tick();
            pre.Reset();
            before.Reset();
            inner.Reset();
            after.Reset();

            // Seventh time, time to go again
            TimeManager.CurrentTime = 15;
            pre.RunningState = RunningState.Failure;
            before.RunningState = RunningState.Success;
            bt.Tick();
            Assertions.AssertWasStartedExecutedAndStopped(before);
            Assertions.AssertWasStartedAndExecuted(inner);
            Assertions.AssertWasNotCalled(after);
        }
    }
}